﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ColorClusteringSOM.Evaluation
{
    class FukuyamaSugeno
    {
        private double[] datasetMEAN = null;    //průměr celého datesetu
        private List<double[]> clustersMEANS = null; //průměr jednotlivých clusterů
        private double fuzier = 0; // musi byt vetsi nez jedna

        private List<NeuronRough> leaders;
        //private int clustersCount;  //pocet klastu  C
        //private int neuronCount;    //pocet neuronu  N


        /// <summary>
        /// Leadri i s aproximacemi
        /// 
        /// </summary>
        /// <param name="leaders"></param>
        /// <param name="fuzier"></param>
        public FukuyamaSugeno(List<NeuronRough> leaders, int fuzier)
        {
            this.leaders = leaders;
            this.fuzier = fuzier;
            clustersMEANS = new List<double[]>();

            ClustersMEANS(); // vypocty prumeru

        }

        /// <summary>
        /// Predpocte se prrumery vsech klastru
        /// </summary>
        private void ClustersMEANS()
        {
            int weightSize = leaders.ElementAt(0).LeaderWeight.Length;
            double[] mean = new double[weightSize]; // prumer datasetu
            double[] meanClus = new double[weightSize]; // pomocna promenna - pro ukladani prumeru jednotlivych klastru
            //pomocne
            int allneuronsCount = 0;    // pomocna pro ulozeni poctu vsech neuronu
            foreach (NeuronRough cluster in leaders) // pocitani prumeru jednotlivzch klastru
            {
                int clusterNeuronCount = cluster.LowerAppNeuronsArray.Count + cluster.UpperAppNeuronsArray.Count; //pocet vsech neuronu v klastru
                allneuronsCount += clusterNeuronCount;
                mean = new double[weightSize];

                if (cluster.LowerAppNeuronsArray.Count != 0 && cluster.UpperAppNeuronsArray.Count !=0)
                {
                    
               
                foreach (NeuronRough neuron in cluster.LowerAppNeuronsArray)
                {
                    for (int i = 0; i < neuron.Neuron.Weights.Length; i++)
                    {
                        meanClus[i] += neuron.Neuron.Weights[i];
                    }
                }

                foreach (NeuronRough neuron in cluster.UpperAppNeuronsArray)
                {
                    for (int i = 0; i < neuron.Neuron.Weights.Length; i++)
                    {
                        meanClus[i] += neuron.Neuron.Weights[i];
                    }
                }
                //soucet vahovych vektoru daneho klastru se deli poctem neuronu
                for (int d = 0; d < meanClus.Length; d++)
                {
                    meanClus[d] /= clusterNeuronCount;
                }
                clustersMEANS.Add(meanClus);
                //tedka to přičteme i do mean coz je prumer celeho datasetu
                for (int d = 0; d < meanClus.Length; d++)
                {
                    mean[d] += meanClus[d];
                }
                }
                else
                {
                    for (int d = 0; d < meanClus.Length; d++)
                    {
                        meanClus[d] = 0;
                    }
                    clustersMEANS.Add(meanClus);
                }
            }
            // vsechny hodnoty jsou secteny ze vsech hlastru a tedka se musi vydelit aby se dostal prumer datasetu
            for (int d = 0; d < meanClus.Length; d++)
            {
                mean[d] /= allneuronsCount;
            }
            datasetMEAN = mean;
        }

        public double FukuyamaSugenoIndex() 
        {
            double INDEX = 0.0; //vysledek
            double uliNAm = 0.0;
            double yes = 1;     // patri do dolni aproximace
            double maybe = 0.5; // patri do horni aproximace
            int clusterNumber = -1;
            foreach (NeuronRough cluster in leaders)
            {
                clusterNumber++;
                double[] clusterMEAN = clustersMEANS.ElementAt(clusterNumber); // data je prumer jednotlivych klastru
                double Zminuses = SquaredEuklid(clusterMEAN, datasetMEAN); ;   // je to euklidovska vzdalenost mezi prumerem klastru a prumerem datasetu na druhou

                uliNAm = Math.Pow(yes, fuzier);     //Uli^m pro dolni app

                foreach (NeuronRough neuron in cluster.LowerAppNeuronsArray)
                {
                    double inThebracket = (SquaredEuklid(neuron.Neuron.Weights, clusterMEAN) - Zminuses);
                    INDEX += uliNAm * inThebracket;
                }
                uliNAm = Math.Pow(maybe, fuzier);     //Uli^m  pro horni app
                foreach (NeuronRough neuron in cluster.UpperAppNeuronsArray)
                {
                    double inThebracket = (SquaredEuklid(neuron.Neuron.Weights, clusterMEAN) - Zminuses);
                    INDEX += uliNAm * inThebracket;
                }
            }
            return INDEX;
        }

        private double SquaredEuklid(double[] input, double[] input2)
        {

            double euDistance = 0;
            double pom = 0;

            for (int i = 0; i < input.Length; i++)
            {
                pom = input[i] - input2[i];
                euDistance += pom * pom;
            }

            return euDistance;
        }


    }
}
